Here is the entire VRML 2.0 source code. Type (or paste) this code into a file called "moveball.wrl".
#VRML V2.0 utf8 PROTO Sony_BindSharedNode [ field SFNode transformNode NULL field SFNode scriptNode NULL ] {} WorldInfo { title "shared ball" info ["VsServer:spiw.com:7009"] } # the object which will be shared DEF OBJ1 Transform { translation 0 0 0 children [ DEF HITME TouchSensor {} Shape { geometry Sphere {} } ] } #script for shared object DEF ScriptObj1 Script { field SFNode obj1 USE OBJ1 eventIn SFTime move eventIn SFString rpc_place_ball eventOut SFVec3f obj1position eventOut SFBool timerEnable url "moveball.class" } DEF CLOCK TimeSensor { loop TRUE enabled TRUE cycleInterval 0.2 stopTime -1 } ROUTE ScriptObj1.obj1position TO OBJ1.set_translation ROUTE ScriptObj1.timerEnable TO CLOCK.set_enabled ROUTE CLOCK.cycleTime TO ScriptObj1.move Sony_BindSharedNode { transformNode USE OBJ1 scriptNode USE ScriptObj1 }
Here is the Java source code. Type this into a file called "moveball.java".
/* This Java file is an example of synchronized multi-user behaviour. The behaviour is of a ball moving in a loop. In all client worlds the ball is synchronized. Written By : Jai Natarajan Sony Pictures Imageworks */ import vrml.*; import vs.*; import java.lang.*; import java.util.*; import java.io.*; public class moveball extends Script { float [] currPos = {0,0,0}; SFNode obj1 = (SFNode)getField("obj1"); Transform objT = (Transform)obj1.getValue(); SFVec3f obj1position = (SFVec3f)getEventOut("obj1position"); SFBool timerOn = (SFBool)getEventOut("timerEnable"); public void moveball () { } // move : called by the timer every tick // ignored by everyone except the master, who updates // position and sends it to the others public void move(ConstSFTime ev, ConstSFTime time) { int j; if(Vscp.amIMaster()) { for(j = 0; j < 3; j++) { currPos[j] += 0.2; currPos[j] = currPos[j] % 5; } String s = createStringFromPos(currPos); Vscp.sendApplSpecificMsgWithDist(obj1, "rpc_place_ball", s,Vscp.allClientsExceptMe); place_ball(); } } // createStringFromPos : takes a position triplet and encodes // as a String to be passed as parameters for the rpc call // (shown in long and painful detail) public String createStringFromPos(float [] pos) { Float f0 = new Float(pos[0]); Float f1 = new Float(pos[1]); Float f2 = new Float(pos[2]); String delim = new String(" "); // delimiter String s00 = f0.toString(); String s0 = s00.concat(delim); String s11 = f1.toString(); String s1 = s11.concat(delim); String s22 = f2.toString(); String s2 = s22.concat(delim); String s01 = s0.concat(s1); String ans = s01.concat(s2); return(ans); } // getPosFromString : retrieves position triplet from String public float [] getPosFromString(String s) { float [] ans = new float[3]; String delim = new String(" "); StringTokenizer st = new StringTokenizer(s, delim); String s0 = st.nextToken(); String s1 = st.nextToken(); String s2 = st.nextToken(); Float f0 = new Float (s0); Float f1 = new Float (s1); Float f2 = new Float (s2); ans[0] = f0.floatValue(); ans[1] = f1.floatValue(); ans[2] = f2.floatValue(); return(ans); } // place_ball : Used by Master to put the ball in its new position public void place_ball () { obj1position.setValue(currPos); } // rpc_place_ball : called in clients (non-master) to positon ball public void rpc_place_ball (ConstSFString data, ConstSFTime time) { currPos = getPosFromString(data.getValue()); place_ball(); } }